package com.bawei.es.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bawei.common.core.domain.R;
import com.bawei.common.core.es.EsIndex;
import com.bawei.common.core.exception.ServiceException;
import com.bawei.common.core.utils.StringUtils;
import com.bawei.es.service.EsDocService;
import com.bawei.es.service.EsIndexService;
import com.bawei.system.domain.dto.EsFindDto;
import com.bawei.system.domain.result.PageResult;
import com.bawei.system.domain.vo.EsDocInsertVo;
import com.bawei.system.domain.vo.EsDocQueryVo;
import com.bawei.system.domain.vo.EsproductInfoVo;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@Log4j2
public class EsDocServiceImpl implements EsDocService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private EsIndexService esIndexService;


    @Override
    public R<Boolean> batchInsertDocs(List<EsDocInsertVo> esDocInsertVo) {
        BulkRequest request = new BulkRequest();
        esDocInsertVo.forEach(e -> {
            IndexRequest source = new IndexRequest(e.getIndexName()).source(e.getData(), XContentType.JSON);
            if (StringUtils.isNotEmpty(e.getId())) {
                source.id(e.getId());
            }
            request.add(source);
        });
        try {
            BulkResponse bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
            return R.ok(true, "插入成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return R.fail(false, "插入失败");
    }

    //检索
    @Override
    public R<List<Map<String,Object>>> queryDocs(EsDocQueryVo esDocInsertVo) {
        //参数校验
//        if (StringUtils.isEmpty(esDocInsertVo.getKeyWord())) {
//            throw new ServiceException("搜索参数不可以为空");
//        }
        if (StringUtils.isEmpty(esDocInsertVo.getIndexName()) || CollectionUtils.isEmpty(esDocInsertVo.getSearchFileds())) {
            throw new ServiceException("索引名或搜索字段列表不能为空");
        }
        try {
        SearchRequest searchRequest = new SearchRequest(esDocInsertVo.getIndexName());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        List<String> searchFields = esDocInsertVo.getSearchFileds();
        //不传keyWord，不做模糊查询
        if (StringUtils.isNotEmpty(esDocInsertVo.getKeyWord())) {
            for (String field : searchFields) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(field, esDocInsertVo.getKeyWord()));
            }
        }
        // 分页
        searchSourceBuilder.from((esDocInsertVo.getPageVo().getCurrentPage() - 1) * esDocInsertVo.getPageVo().getPageSize());
        searchSourceBuilder.size(esDocInsertVo.getPageVo().getPageSize());
        searchSourceBuilder.query(boolQueryBuilder);
        // 创建一个HighlightBuilder
        HighlightBuilder highlightBuilder = new HighlightBuilder();

        List<String> highLightFileds = esDocInsertVo.getHighLightFileds();
        if(CollectionUtils.isEmpty(highLightFileds)){

        }
        for (String field : searchFields) {
            highlightBuilder.field(field).preTags("<span style='color:red'>").postTags("</span>");
        }
        searchSourceBuilder.highlighter(highlightBuilder);
        // 将SearchSourceBuilder设置到SearchRequest中
        searchRequest.source(searchSourceBuilder);
        // 接下来发送搜索请求并处理结果
            SearchResponse esSearchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits esSearchHits = esSearchResponse.getHits();
            //校验是否查询到数据
            if (esSearchHits.getHits().length == 0) {
                // 若未查询到结果，直接进行返回
                return R.ok(Collections.emptyList());
            }
            List<Map<String, Object>> productInfoResponseList = new ArrayList<>();
            for (SearchHit searchHit : esSearchHits.getHits()) {
                // 源数据
                String sourceAsString = searchHit.getSourceAsString();
                Map<String, Object> productInfoResponse =
                        JSONObject.parseObject(sourceAsString, Map.class);
                // 高亮
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                if (highlightFields != null) {
                    for (String field : searchFields) { // 假设fileds是期望被高亮的字段列表
                        HighlightField highlightField = highlightFields.get(field);
                        if (highlightField != null) {
                            // 拼装
                            Text[] fragments = highlightField.fragments();
                            StringBuilder stringBuilder = new StringBuilder();
                            for (Text fragment : fragments) {
                                stringBuilder.append(fragment.string()).append("..."); // 可以添加分隔符
                            }
                            // 去除尾部的分隔符（如果需要）
                            if (stringBuilder.length() > 0) {
                                stringBuilder.setLength(stringBuilder.length() - 3);
                            }
                            productInfoResponse.put(field, stringBuilder.toString());
                        }
                    }
                }
                productInfoResponseList.add(productInfoResponse);
            }
            return R.ok(productInfoResponseList);
        } catch (IOException e) {
            // 提供更具体的异常信息
            throw new RuntimeException("Elasticsearch search failed", e);
        }
    }


    //定义好入参、返回值、远程调用
    @Override
    public void deleteId(List<String> ids, String indexName) {
        for (String id : ids) {
            DeleteRequest deleteRequest = new DeleteRequest(indexName, id);
            try {
                DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
                // 可以检查删除操作的结果
                if (deleteResponse.getResult() == DocWriteResponse.Result.DELETED) {
                    System.out.println("Document with ID " + id + " has been deleted.");
                } else {
                    System.out.println("Document with ID " + id + " was not found or could not be deleted.");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

//联想自动补全
    @Override
    public R querySuggestions(String indexName, String keyWord, String suggesFiled) {
        if (!esIndexService.indexExit(indexName).getData()) {
            throw new RuntimeException("索引不存在");
        }
        SearchRequest request = new SearchRequest(indexName);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion(
                EsIndex.TITLESUGGEST,
                SuggestBuilders.completionSuggestion(suggesFiled)
                        .prefix(keyWord)
                        .skipDuplicates(true)
                        .size(10)
        );
        searchSourceBuilder.suggest(suggestBuilder);
        request.source(searchSourceBuilder);

        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            String message = e.getMessage();
            if (message.contains("field not exists")) { // 注意这里应该是 "field" 而不是 "filed"
                message = "es索引下的字段不存在";
            }
            throw new RuntimeException(message, e); // 最好保留原始异常信息
        }

        if (response != null && response.getSuggest() != null) {
            Suggest suggest = response.getSuggest();
            ArrayList<String> list = new ArrayList<>();
            Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> suggestion = suggest.getSuggestion(EsIndex.TITLESUGGEST);
            if (suggestion != null) {
                for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> entry : suggestion.getEntries()) {
                    for (Suggest.Suggestion.Entry.Option option : entry.getOptions()) {
                        list.add(option.getText().toString()); // 使用 toString() 而不是 string()
                    }
                }
            }
            return R.ok(list);
        }
        return R.ok(new ArrayList<>()); // 如果没有建议，返回空列表
    }


    //es普通查询
    @Override
    public PageResult<EsproductInfoVo> find(EsFindDto esFindDto) {
        long total=0;
        ArrayList<EsproductInfoVo> list = new ArrayList<>();
        try {
            SearchRequest searchRequest = new SearchRequest(EsIndex.PRODUCT_INFO);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //名称模糊查询
            if(StringUtils.isNotEmpty(esFindDto.getName())){
                boolQueryBuilder.must(QueryBuilders.matchQuery(EsIndex.NAME,esFindDto.getName()));
            }
            //区间查询
            if(esFindDto.getStartTime()!=null){
                boolQueryBuilder.must(QueryBuilders.rangeQuery(EsIndex.CREATETIME).gte(esFindDto.getStartTime().getTime()));
            }
            if(esFindDto.getEndTime()!=null){
                boolQueryBuilder.must(QueryBuilders.rangeQuery(EsIndex.CREATETIME).lte(esFindDto.getEndTime().getTime()));
            }

            searchSourceBuilder.query(boolQueryBuilder);
            //分页
            searchSourceBuilder.from((esFindDto.getPageNum()-1)*esFindDto.getPageSize());
            searchSourceBuilder.size(esFindDto.getPageSize());
            //排序
            searchSourceBuilder.sort(EsIndex.CREATETIME, SortOrder.ASC);
            //高亮
            searchSourceBuilder.highlighter(new HighlightBuilder()
                    .field(EsIndex.NAME)
                    .preTags("<span style=\"color: red\">")
                    .postTags("</span>\n"));

            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();
            //获取条数
            total = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                EsproductInfoVo esproductInfoVo = JSONObject.parseObject(sourceAsString, EsproductInfoVo.class);
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                if(highlightFields!=null){
                    HighlightField highlightField = highlightFields.get(EsIndex.NAME);
                    if(highlightField!=null){
                        StringBuilder stringBuilder = new StringBuilder();
                        Text[] fragments = highlightField.fragments();
                        for (Text fragment : fragments) {
                            stringBuilder.append(fragment);
                        }
                        esproductInfoVo.setName(String.valueOf(stringBuilder));
                    }
                }
                esproductInfoVo.setSpuId(Long.valueOf(searchHit.getId()));
                list.add(esproductInfoVo);
            }
        }catch (Exception e){
            log.error("异常："+e);
        }
        return PageResult.toPageResult(total,list);
    }
}
